<?php

declare(strict_types=1);

namespace Phpben\Imi\Auth;

use Imi\Db\Db;

class Auth
{
    public $config = [];

    public $user_id = null;

    protected static $instance = null;

    public function __construct($options = [])
    {
        $this->options = $options;
        foreach ($options as $k => $v) {
            $this->{$k} = is_array($v) ? json_decode(json_encode($v)) : $v;
        }
    }

    public static function instance($options = [])
    {
        if (is_null(self::$instance)) {
            self::$instance = new static($options);
        }
        return self::$instance;
    }

    /**
     * 设置用户ID
     * @param int $user_id
     * @return $this
     */
    public function setUserId(int $user_id)
    {
        $this->user_id = $user_id;
        return $this;
    }

    /**
     * 获取用户组
     * @return array
     */
    public function getGroups(): array
    {
        $auth_group_access = $this->model->auth_group_access::__getMeta()->getTableName();
        $auth_group = $this->model->auth_group::__getMeta()->getTableName();
        return Db::query()->table($auth_group_access)
            ->leftJoin($auth_group, $auth_group . '.id', '=', $auth_group_access . '.' . $this->settings->auth_group_access_keys->group_id)
            ->where($auth_group_access . '.' . $this->settings->auth_group_access_keys->user_id, '=', $this->user_id)
            ->where($auth_group . '.' . $this->settings->auth_group_keys->status, '=', 1)
            ->field($auth_group_access . '.' . $this->settings->auth_group_access_keys->user_id, $auth_group_access . '.' . $this->settings->auth_group_access_keys->group_id, $auth_group . '.*')
            ->select()->getArray();
    }

    /**
     * 取用户组树状结构
     * @return array
     */
    public function getGroupList(): array
    {
        $groups = $this->getGroups();
        $groupIds = [];
        foreach ($groups as $k => $v) {
            $groupIds[] = $v['id'];
        }
        $originGroupIds = $groupIds;
        foreach ($groups as $k => $v) {
            if (in_array($v[$this->settings->auth_group_keys->pid], $originGroupIds)) {
                $groupIds = array_diff($groupIds, [$v['id']]);
                unset($groups[$k]);
            }
        }
        $list = [];
        foreach ($groups as $k => &$v) {
            if ($v[$this->settings->auth_group_keys->ids] == '*') {
                return $this->model->auth_group::getAssocList();
            }
            $data = $this->model->auth_group::find($v['id']);
            $ids = $data->getChildrenIds(null, true);
            $list[] = $this->model->auth_group::getAssocList($this->model->auth_group::query()->whereIn('id', $ids))[0] ?? $data->toArray();
        }
        return $list;
    }

    /**
     * 取当前用户组所有id
     * @param bool $withself 是否包含当前所在的分组
     * @return array
     */
    public function getChildrenGroupIds(bool $withself = false): array
    {
        $groups = $this->getGroups();
        $groupIds = [];
        foreach ($groups as $k => $v) {
            $groupIds[] = $v['id'];
        }
        $originGroupIds = $groupIds;
        foreach ($groups as $k => $v) {
            if (in_array($v[$this->settings->auth_group_keys->pid], $originGroupIds)) {
                $groupIds = array_diff($groupIds, [$v['id']]);
                unset($groups[$k]);
            }
        }
        $list = [];
        foreach ($groups as $k => &$v) {
            if ($v[$this->settings->auth_group_keys->ids] == '*') {
                return $this->model->auth_group::query()->field('id')->select()->getColumn();
            }
            $data = $this->model->auth_group::find($v['id']);
            $ids = $data->getChildrenIds(null, true);
            $list = array_merge($list, $ids ?: [$v['id']]);
        }
        if (!$withself) {
            $list = array_diff($list, $groupIds);
        }
        return $list;
    }

    /**
     * 取出当前管理员所拥有权限的管理员
     * @param bool $withself 是否包含自身
     * @return array
     */
    public function getChildrenAdminIds(bool $withself = false): array
    {
        $childrenAdminIds = [];
        if (!$this->isSuper()) {
            $groupIds = $this->getChildrenGroupIds();
            $authGroupList = $groupIds ? $this->model->auth_group_access::query()
                ->field($this->settings->auth_group_access_keys->user_id, $this->settings->auth_group_access_keys->group_id)
                ->whereIn($this->settings->auth_group_access_keys->group_id, $groupIds)
                ->select()
                ->getArray() : [];
            foreach ($authGroupList as $k => $v) {
                $childrenAdminIds[] = $v[$this->settings->auth_group_access_keys->user_id];
            }
        } else {
            //超级管理员拥有所有人的权限
            $childrenAdminIds = $this->model->user::query()->field('id')->select()->getColumn();
        }
        if ($withself) {
            if (!in_array($this->user_id, $childrenAdminIds)) {
                $childrenAdminIds[] = $this->user_id;
            }
        } else {
            $childrenAdminIds = array_diff($childrenAdminIds, [$this->user_id]);
        }
        return $childrenAdminIds;
    }

    /**
     * 用户是否为超级组
     * @return bool
     */
    public function isSuper(): bool
    {
        return in_array('*', $this->getRuleIds());
    }

    /**
     * 用户对应规则ids
     * @return array
     */
    public function getRuleIds(): array
    {
        $user_groups = $this->getGroups();
        $ids = [];
        foreach ($user_groups as $g) {
            $ids = array_merge($ids, array_filter(explode(',', $g[$this->settings->auth_group_keys->ids])));
        }
        return array_unique($ids);
    }

    /**
     * 用户规则列表
     * @param bool $check
     * @return array
     */
    public function getRuleList(bool $check = false): array
    {
        $ids = $this->getRuleIds();
        if (empty($ids)) {
            return [];
        }
        if (in_array('*', $ids) && $check) {
            return ['*'];
        }
        $auth_rule = $this->model->auth_rule::query();
        !in_array('*', $ids) && $auth_rule->whereIn('id', $ids);
        $rules = $auth_rule->order('sort', 'desc')->select();
        $rulelist = [];
        foreach ($rules->getArray() as $rule) {
            $rulelist[$rule['id']] = $rule[$this->settings->auth_rule_keys->rule];
        }
        return $rulelist;
    }
}